#pragma once
#include <vector>
#include <queue>
#include <unistd.h>
#include "thread.hpp"

const int g_thread_num = 2;

template <class T>
class ThreadPool
{
private:
    ThreadPool(int num = g_thread_num) : _num(num) // 线程池内线程数量
    {
        for (int i = 0; i < _num; i++)
        {
            threadPool.push_back(new Thread(i + 1, routine, NULL)); // 创建线程实例，放入线程池
        }
        task_rq = new RingQueue<T>(); // 创建任务队列
    }
    ThreadPool(const ThreadPool<T> &tp) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &tp) = delete;
    // 构造私有,赋值和拷贝删除
public:
    static ThreadPool<T> *getInstance() // 懒汉模式:第一次获取单例时再new
    {
        if (_instance == nullptr) // 外层判断是为了避免锁竞争，不必每次获取单例都要加锁
        {
            // 多线程下不安全，需要加锁保护
            pthread_mutex_lock(&singleTon_mtx);
            if (_instance == nullptr) // 里层判断是确保就算进入多个线程，也只有一个线程能new单例
            {
                _instance = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&singleTon_mtx);
        }
        return _instance;
    }
    void run()
    {
        for (int i = 0; i < _num; i++)
        {
            threadPool[i]->getTPool((void *)this); // 传入当前线程池的指针
            threadPool[i]->start();                // 线程池内所有线程启动
        }
    }
    void pushTask(const T &task) // 添加任务
    {
        task_rq->Push(task);
    }
    T popTask() // 线程获取任务
    {
        T task;
        task_rq->Pop(task);
        return task;
    }
    ~ThreadPool()
    {
        for (int i = 0; i < _num; i++)
        {
            threadPool[i]->join();
            delete threadPool[i]; // 等待所有线程退出，delete Thread实例
        }
        delete task_rq; // 销毁任务队列
    }

private:
    vector<Thread *> threadPool; // 线程池
    int _num;                    // 线程数量

    RingQueue<T> *task_rq; // 使用生产者消费者模型实现放任务与取任务的互斥与同步

    static void *routine(void *TData) // 1.线程启动后就进入这个函数 2.若为非静态函数，有一个隐藏this指针，可能会报错
    {
        ThreadData *td = (ThreadData *)TData;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_tp; // 获取到线程池
        while (true)
        {
            // sleep(1);
            // 获取到任务并执行，若没有任务则阻塞
            T task = tp->popTask();
            task(); // 执行任务
        }
    }

    static ThreadPool<T> *_instance;      // 类内声明
    static pthread_mutex_t singleTon_mtx; // 为了保护懒汉模式线程安全
};

template <class T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr; // 类外定义
template <class T>
pthread_mutex_t ThreadPool<T>::singleTon_mtx = PTHREAD_MUTEX_INITIALIZER;